package net.media.datafw.transport.transporters;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import net.media.datafw.transport.TransportException;
import net.media.datafw.transport.Transporter;
import net.media.datafw.transport.model.TransportField;
import net.media.datafw.transport.model.Transportable;
import net.media.datafw.transport.utils.TransporterUtil;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

public class PListTransporter extends Transporter {
	private static final String PLIST_ROOT = "plist";
	private static final String PLIST_DICT = "dict";
	private static final String PLIST_ARRAY = "array";
	private static final String PLIST_KEY = "key";
	private static final String PLIST_STRING = "string";
	private static final String PLIST_REAL = "real";
	private static final String PLIST_INT = "integer";
	private static final String PLIST_BOOLEAN_TRUE = "true";
	private static final String PLIST_BOOLEAN_FALSE = "false";

	Document document = null;
	DocumentBuilder documentBuilder = null;
	Element rootElement = null;

	@Override
	protected void writeTransportable(Transportable data, Object serilizedData) throws TransportException {
		try {
			Element transportableDictKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(readClassName(data.getClass()));
			transportableDictKey.appendChild(textNode);
			Element transportableDictValue = document.createElement(PLIST_DICT);
			serializeTransportable(data, transportableDictValue);
			((Element) serilizedData).appendChild(transportableDictKey);
			((Element) serilizedData).appendChild(transportableDictValue);
		} catch (Exception e) {
			throw new TransportException(e);
		}

	}

	@Override
	protected void writeTransportableArray(Transportable[] data, Object serilizedData) throws TransportException {
		try {
			if (data != null) {
				for (int i = 0; i < data.length; i++) {
					Element transportableDict = document.createElement(PLIST_DICT);
					writeTransportable(data[i], transportableDict);
					((Element) serilizedData).appendChild(transportableDict);
				}
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeTransportable(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			if (field.isArray()) {
				Transportable[] transportableArray = (Transportable[]) objectData;
				Element transportableJSONArray = document.createElement(PLIST_ARRAY);
				for (int i = 0; i < transportableArray.length; i++) {
					Element transportableDict = document.createElement(PLIST_DICT);
					Element transportableDictKey = document.createElement(PLIST_KEY);
					Text arrayTextNode = document.createTextNode(readClassName(objectData.getClass().getComponentType()));
					transportableDictKey.appendChild(arrayTextNode);
					Element transportableDictValue = document.createElement(PLIST_DICT);
					serializeTransportable((Transportable) transportableArray[i], transportableDictValue);
					transportableDict.appendChild(transportableDictKey);
					transportableDict.appendChild(transportableDictValue);
					((Element) transportableJSONArray).appendChild(transportableDict);
				}
				((Element) serializedData).appendChild(transportableJSONArray);
			} else {
				Element transportableDict = document.createElement(PLIST_DICT);
				Element transportableDictKey = document.createElement(PLIST_KEY);
				Text elementtextNode = document.createTextNode(readClassName(objectData.getClass()));
				transportableDictKey.appendChild(elementtextNode);
				Element transportableDictValue = document.createElement(PLIST_DICT);
				serializeTransportable((Transportable) objectData, transportableDictValue);
				transportableDict.appendChild(transportableDictKey);
				transportableDict.appendChild(transportableDictValue);
				((Element) serializedData).appendChild(transportableDict);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected Object initialiseTrasportableArray() throws TransportException {

		if (document == null) {
			document = createDocument();
		}
		rootElement = document.createElement(PLIST_ROOT);
		Element arrayElement = document.createElement(PLIST_ARRAY);
		rootElement.appendChild(arrayElement);

		return arrayElement;
	}

	@Override
	protected Object initialiseTrasportable() throws TransportException {
		if (document == null) {
			document = createDocument();
		}
		rootElement = document.createElement(PLIST_ROOT);
		Element dictElement = document.createElement(PLIST_DICT);
		rootElement.appendChild(dictElement);
		return dictElement;
	}

	private Document createDocument() throws TransportException {
		Document document = null;
		try {
			if (documentBuilder == null) {
				documentBuilder = createDocumentBuilder();
			}
			document = documentBuilder.newDocument();
		} catch (Exception e) {
			throw new TransportException(e);
		}
		return document;
	}

	private DocumentBuilder createDocumentBuilder() throws TransportException {
		try {
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			return documentBuilder = documentBuilderFactory.newDocumentBuilder();
		} catch (Exception e) {
			throw new TransportException(e);
		}

	}

	@Override
	protected void serializeBoolean(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> clazz;
			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				boolean[] data;
				if (clazz.isPrimitive()) {
					data = (boolean[]) objectData;
				} else {
					Boolean[] dataArr = (Boolean[]) objectData;
					data = TransporterUtil.converBooleanArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = null;
					if (data[dataIdx]) {
						arrayElement = document.createElement(PLIST_BOOLEAN_TRUE);
					} else {
						arrayElement = document.createElement(PLIST_BOOLEAN_FALSE);
					}

					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element valueElement = null;
				if (((Boolean) objectData).booleanValue()) {
					valueElement = document.createElement(PLIST_BOOLEAN_TRUE);
				} else {
					valueElement = document.createElement(PLIST_BOOLEAN_FALSE);
				}
				((Element) serializedData).appendChild(valueElement);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeByte(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Class<?> clazz;

			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				byte[] data;
				if (clazz.isPrimitive()) {
					data = (byte[]) objectData;
				} else {
					Byte[] dataArr = (Byte[]) objectData;
					data = TransporterUtil.converByteArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_INT);
					Text keyTextNode = document.createTextNode(((Byte) data[dataIdx]).toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_INT);
				Text textValueNode = document.createTextNode(((Byte) objectData).toString());
				transportableValue.appendChild(textValueNode);
				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeCharacter(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> clazz;
			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				char[] data;
				if (clazz.isPrimitive()) {
					data = (char[]) objectData;
				} else {
					Character[] dataArr = (Character[]) objectData;
					data = TransporterUtil.converCharacterArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_STRING);
					Text keyTextNode = document.createTextNode(((Character) data[dataIdx]).toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_STRING);
				Text textValueNode = document.createTextNode(((Character) objectData).toString());
				transportableValue.appendChild(textValueNode);

				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeShort(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> clazz;
			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				short[] data;
				if (clazz.isPrimitive()) {
					data = (short[]) objectData;
				} else {
					Short[] dataArr = (Short[]) objectData;
					data = TransporterUtil.converShortArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_INT);
					Text keyTextNode = document.createTextNode(((Short) data[dataIdx]).toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_INT);
				Text textValueNode = document.createTextNode(((Short) objectData).toString());
				transportableValue.appendChild(textValueNode);

				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeInteger(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> clazz;
			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				int[] data;
				if (clazz.isPrimitive()) {
					data = (int[]) objectData;
				} else {
					Integer[] dataArr = (Integer[]) objectData;
					data = TransporterUtil.converIntegerArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_INT);
					Text keyTextNode = document.createTextNode(((Integer) data[dataIdx]).toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_INT);
				Text textValueNode = document.createTextNode(((Integer) objectData).toString());
				transportableValue.appendChild(textValueNode);

				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeLong(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> clazz;
			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				long[] data;
				if (clazz.isPrimitive()) {
					data = (long[]) objectData;
				} else {
					Long[] dataArr = (Long[]) objectData;
					data = TransporterUtil.converLongArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_INT);
					Text keyTextNode = document.createTextNode(((Long) data[dataIdx]).toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_INT);
				Text textValueNode = document.createTextNode(((Long) objectData).toString());
				transportableValue.appendChild(textValueNode);

				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeFloat(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> clazz;
			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				float[] data;
				if (clazz.isPrimitive()) {
					data = (float[]) objectData;
				} else {
					Float[] dataArr = (Float[]) objectData;
					data = TransporterUtil.converFloatArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_REAL);
					Text keyTextNode = document.createTextNode(((Float) data[dataIdx]).toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_REAL);
				Text textValueNode = document.createTextNode(((Float) objectData).toString());
				transportableValue.appendChild(textValueNode);

				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeDouble(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> clazz;
			if (field.isArray()) {
				clazz = ((Class<?>) field.getType()).getComponentType();
				double[] data;
				if (clazz.isPrimitive()) {
					data = (double[]) objectData;
				} else {
					Double[] dataArr = (Double[]) objectData;
					data = TransporterUtil.converDoubleArray(dataArr);
				}

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_REAL);
					Text keyTextNode = document.createTextNode(((Double) data[dataIdx]).toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_REAL);
				Text textValueNode = document.createTextNode(((Double) objectData).toString());
				transportableValue.appendChild(textValueNode);

				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeString(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			if (field.isArray()) {
				String[] data = (String[]) objectData;

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_STRING);
					Text keyTextNode = document.createTextNode((String) data[dataIdx]);
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_STRING);
				Text textValueNode = document.createTextNode((String) objectData);
				transportableValue.appendChild(textValueNode);
				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void serializeDate(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			if (field.isArray()) {
				Date[] data = (Date[]) objectData;

				Element transportablePListArray = document.createElement(PLIST_ARRAY);

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_STRING);
					Text keyTextNode = document.createTextNode(data[dataIdx].toString());
					arrayElement.appendChild(keyTextNode);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				Element transportableValue = document.createElement(PLIST_STRING);
				Text textValueNode = document.createTextNode(objectData.toString());
				transportableValue.appendChild(textValueNode);
				((Element) serializedData).appendChild(transportableValue);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void serializeArrayList(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			Class<?> genericValueClass = (Class<?>) field.getComponentValueType();

			if (field.isArray()) {
				Element transportablePListArray = document.createElement(PLIST_ARRAY);
				ArrayList<Object>[] data = (ArrayList<Object>[]) objectData;

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_ARRAY);
					processArrayList(field, data[dataIdx], genericValueClass, arrayElement);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				ArrayList<Object> data = (ArrayList<Object>) objectData;
				Element serializedDataArray = document.createElement(PLIST_ARRAY);
				processArrayList(field, data, genericValueClass, serializedDataArray);
				((Element) serializedData).appendChild(serializedDataArray);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void processArrayList(TransportField field, ArrayList<Object> data, Type genericValueClass, Object serializedData) throws TransportException {
		try {
			if ((Boolean.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = null;

					if (((Boolean) data.get(arrarIdx)).booleanValue()) {
						arrayListItem = document.createElement(PLIST_BOOLEAN_TRUE);
					} else {
						arrayListItem = document.createElement(PLIST_BOOLEAN_FALSE);
					}
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Byte.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNode = document.createTextNode(((Byte) data.get(arrarIdx)).toString());
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Character.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_STRING);
					Text textNode = document.createTextNode(((Character) data.get(arrarIdx)).toString());
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Short.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNode = document.createTextNode(((Short) data.get(arrarIdx)).toString());
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Integer.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNode = document.createTextNode(((Integer) data.get(arrarIdx)).toString());
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Long.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNode = document.createTextNode(((Long) data.get(arrarIdx)).toString());
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Float.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_REAL);
					Text textNode = document.createTextNode(((Float) data.get(arrarIdx)).toString());
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Double.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_REAL);
					Text textNode = document.createTextNode(((Double) data.get(arrarIdx)).toString());
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((String.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_STRING);
					Text textNode = document.createTextNode((String) data.get(arrarIdx));
					arrayListItem.appendChild(textNode);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if (isTransportable(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < data.size(); arrarIdx++) {
					Element arrayListItem = document.createElement(PLIST_DICT);
					writeTransportable((Transportable) data.get(arrarIdx), arrayListItem);
					((Element) serializedData).appendChild(arrayListItem);
				}
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void serializeHashMap(TransportField field, Object objectData, Object serializedData) throws TransportException {
		try {
			Element transportableKey = document.createElement(PLIST_KEY);
			Text textNode = document.createTextNode(field.getName());
			transportableKey.appendChild(textNode);
			((Element) serializedData).appendChild(transportableKey);

			if (field.isArray()) {
				Element transportablePListArray = document.createElement(PLIST_ARRAY);
				HashMap<Object, Object>[] data = (HashMap<Object, Object>[]) objectData;

				for (int dataIdx = 0; dataIdx < data.length; dataIdx++) {
					Element arrayElement = document.createElement(PLIST_DICT);
					processHashMap(field, data[dataIdx], field.getComponentValueType(), arrayElement);
					transportablePListArray.appendChild(arrayElement);
				}
				((Element) serializedData).appendChild(transportablePListArray);
			} else {
				HashMap<Object, Object> data = (HashMap<Object, Object>) objectData;
				Element serializedDataArray = document.createElement(PLIST_DICT);
				processHashMap(field, data, field.getComponentValueType(), serializedDataArray);
				((Element) serializedData).appendChild(serializedDataArray);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void processHashMap(TransportField field, HashMap<Object, Object> data, Type genericValueClass, Object serializedData) throws TransportException {

		try {
			Iterator<?> keyIterator = data.keySet().iterator();

			if ((Boolean.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = null;
					if (((Boolean) data.get(key)).booleanValue()) {
						arrayListItem = document.createElement(PLIST_BOOLEAN_TRUE);
					} else {
						arrayListItem = document.createElement(PLIST_BOOLEAN_FALSE);
					}
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Byte.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNodeValue = document.createTextNode(((Byte) data.get(key)).toString());
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Character.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_STRING);
					Text textNodeValue = document.createTextNode(((Character) data.get(key)).toString());
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Short.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNodeValue = document.createTextNode(((Short) data.get(key)).toString());
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Integer.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNodeValue = document.createTextNode(((Integer) data.get(key)).toString());
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Long.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_INT);
					Text textNodeValue = document.createTextNode(((Long) data.get(key)).toString());
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Float.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_REAL);
					Text textNodeValue = document.createTextNode(((Float) data.get(key)).toString());
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((Double.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_REAL);
					Text textNodeValue = document.createTextNode(((Double) data.get(key)).toString());
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if ((String.class).equals(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_REAL);
					Text textNodeValue = document.createTextNode((String) data.get(key));
					arrayListItem.appendChild(textNodeValue);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			} else if (isTransportable(genericValueClass)) {
				while (keyIterator.hasNext()) {
					String key = (String) keyIterator.next();
					Element transportableKey = document.createElement(PLIST_KEY);
					Text textNodeKey = document.createTextNode(key);
					transportableKey.appendChild(textNodeKey);
					Element arrayListItem = document.createElement(PLIST_DICT);
					writeTransportable((Transportable) data.get(key), arrayListItem);
					((Element) serializedData).appendChild(transportableKey);
					((Element) serializedData).appendChild(arrayListItem);
				}
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void onSerializeField(TransportField field, Object serializedData) throws TransportException {
	}

	@Override
	protected void afterSerializeField(ArrayList<TransportField> fields, Object serializedData) throws TransportException {
	}

	@Override
	protected Object parseData(byte[] dataString) throws TransportException {
		try {
			ByteArrayInputStream bais = new ByteArrayInputStream(dataString);
			Document dataDocument = documentBuilder.parse(bais);
			Node root = dataDocument.getFirstChild();
			return root;
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected Class<?> readClass(Object serializedData) throws TransportException {
		Element serializedDataElement = (Element) serializedData;
		return classNames.get(((serializedDataElement.getChildNodes()).item(0)).getTextContent());
	}

	@Override
	protected Object getTransportable(Object serializedData) {
		return serializedData;
	}

	@Override
	protected boolean isTransportableArray(Object serializedData) {
		return Boolean.valueOf(((Element) serializedData).getNodeName() == PLIST_ARRAY);
	}

	@Override
	protected Object readTransportableArray(Object serializedData) throws TransportException {
		Object[] transpotableArray = null;
		try {
			NodeList transportableArray = ((Element) serializedData).getChildNodes();
			if (transportableArray != null && transportableArray.getLength() > 0) {
				transpotableArray = new Object[transportableArray.getLength()];

				for (int arrayIdx = 0; arrayIdx < transportableArray.getLength(); arrayIdx++) {
					transpotableArray[arrayIdx] = readTransportable(transportableArray.item(arrayIdx));
				}
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
		return transpotableArray;
	}

	@Override
	protected Object readTransportable(Object serializedData) throws TransportException {
		Object transpotableObject = null;
		try {
			Class<?> clazz = readClass(serializedData);
			if (clazz.isArray()) {
				clazz = clazz.getComponentType();
			}

			transpotableObject = clazz.newInstance();

			Element transportableObject = (Element) serializedData;
			if (transportableObject != null) {
				ArrayList<TransportField> fields = classFields.get(clazz);
				if (fields != null) {
					HashMap<String, Object> xmlData = readXMLElements(((Element) serializedData).getChildNodes().item(1));
					for (int fieldIdx = 0; fieldIdx < fields.size(); fieldIdx++) {
						TransportField field = fields.get(fieldIdx);
						Object value = xmlData.get(field.getName());

						if (value != null/* && isprimitiveAndHasValue(field, value)*/) {
							deserializeField(field, value, transpotableObject);
						}
					}
				}
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
		return transpotableObject;
	}

	@Override
	protected void deserializedTransportable(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				NodeList transportableXMLArray = ((Element) objectData).getChildNodes();
				Transportable[] transportableArray = new Transportable[transportableXMLArray.getLength()];
				for (int i = 0; i < transportableXMLArray.getLength(); i++) {
					transportableArray[i] = (Transportable) readTransportable(transportableXMLArray.item(i));
				}
				field.setValue(deserializedObject, transportableArray);
			} else {
				Transportable obj = (Transportable) readTransportable((Element) objectData);
				field.setValue(deserializedObject, obj);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeBoolean(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Boolean[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Boolean[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = Boolean.valueOf((xmlArray.item(dataIdx)).getNodeName());
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converBooleanArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, Boolean.valueOf(((Element) objectData).getNodeName()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeByte(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Byte[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Byte[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = Byte.valueOf((xmlArray.item(dataIdx)).getTextContent());
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converByteArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, Byte.valueOf(((Element) objectData).getTextContent()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeCharacter(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Character[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Character[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = (xmlArray.item(dataIdx)).getTextContent().charAt(0);
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converCharacterArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, (((Element) objectData).getTextContent()).charAt(0));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeShort(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Short[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Short[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = Short.valueOf((xmlArray.item(dataIdx)).getTextContent());
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converShortArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, Short.valueOf(((Element) objectData).getTextContent()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeInteger(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Integer[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Integer[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = Integer.valueOf((xmlArray.item(dataIdx)).getTextContent());
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converIntegerArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, Integer.valueOf(((Element) objectData).getTextContent()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeLong(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Long[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Long[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = Long.valueOf((xmlArray.item(dataIdx)).getTextContent());
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converLongArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, Long.valueOf(((Element) objectData).getTextContent()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeFloat(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Float[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Float[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = Float.valueOf((xmlArray.item(dataIdx)).getTextContent());
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converFloatArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, Float.valueOf(((Element) objectData).getTextContent()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeDouble(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Double[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Double[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = Double.valueOf((xmlArray.item(dataIdx)).getTextContent());
					}
				}

				if (((Class<?>) field.getType()).getComponentType().isPrimitive()) {
					field.setValue(deserializedObject, TransporterUtil.converDoubleArray(fieldValue));
				} else {
					field.setValue(deserializedObject, fieldValue);
				}
			} else {
				field.setValue(deserializedObject, Double.valueOf(((Element) objectData).getTextContent()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeString(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				String[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new String[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = (xmlArray.item(dataIdx)).getTextContent();
					}
				}

				field.setValue(deserializedObject, fieldValue);
			} else {
				field.setValue(deserializedObject, ((Element) objectData).getTextContent());
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected void deserializeDate(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			if (field.isArray()) {
				Date[] fieldValue = null;
				NodeList xmlArray = ((Element) objectData).getChildNodes();
				if (xmlArray != null && xmlArray.getLength() > 0) {
					fieldValue = new Date[xmlArray.getLength()];

					for (int dataIdx = 0; dataIdx < xmlArray.getLength(); dataIdx++) {
						fieldValue[dataIdx] = simpleDateFormat.parse((xmlArray.item(dataIdx)).getTextContent());
					}
				}

				field.setValue(deserializedObject, fieldValue);
			} else {
				field.setValue(deserializedObject, simpleDateFormat.parse(((Element) objectData).getTextContent()));
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}

	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	protected void deserializeArrayList(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			Class<?> genericValueClass = (Class<?>) field.getComponentValueType();

			if (field.isArray()) {
				NodeList serializedDataArray = ((Element) objectData).getChildNodes();
				ArrayList[] deserializedDataArray = new ArrayList[serializedDataArray.getLength()];
				for (int dataIdx = 0; dataIdx < serializedDataArray.getLength(); dataIdx++) {
					ArrayList<Object> deserializedDataObject = (ArrayList<Object>) ((Class<?>) field.getRawType()).newInstance();
					readArrayList(field, serializedDataArray.item(dataIdx), genericValueClass, deserializedDataObject);
					deserializedDataArray[dataIdx] = deserializedDataObject;
				}
				field.setValue(deserializedObject, deserializedDataArray);
			} else {
				ArrayList<Object> deserializedDataObject = (ArrayList<Object>) ((Class<?>) field.getRawType()).newInstance();
				readArrayList(field, objectData, genericValueClass, deserializedDataObject);
				field.setValue(deserializedObject, deserializedDataObject);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void readArrayList(TransportField field, Object valueArray, Class<?> genericValueClass, Object deserializedDataObject) throws TransportException {
		try {
			NodeList value = ((Element) valueArray).getChildNodes();

			if ((Boolean.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Boolean>) deserializedDataObject).add(Boolean.valueOf(value.item(arrarIdx).getTextContent()));
				}
			} else if ((Byte.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Byte>) deserializedDataObject).add(Byte.valueOf(value.item(arrarIdx).getTextContent()));
				}
			} else if ((Character.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Character>) deserializedDataObject).add((value.item(arrarIdx).getTextContent()).charAt(0));
				}
			} else if ((Short.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Short>) deserializedDataObject).add(Short.valueOf(value.item(arrarIdx).getTextContent()));
				}
			} else if ((Integer.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Integer>) deserializedDataObject).add(Integer.valueOf(value.item(arrarIdx).getTextContent()));
				}
			} else if ((Long.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Long>) deserializedDataObject).add(Long.valueOf(value.item(arrarIdx).getTextContent()));
				}
			} else if ((Float.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Float>) deserializedDataObject).add(Float.valueOf(value.item(arrarIdx).getTextContent()));
				}
			} else if ((Double.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Double>) deserializedDataObject).add(Double.valueOf(value.item(arrarIdx).getTextContent()));
				}
			} else if ((String.class).equals(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<String>) deserializedDataObject).add(value.item(arrarIdx).getTextContent());
				}
			} else if (isTransportable(genericValueClass)) {
				for (int arrarIdx = 0; arrarIdx < value.getLength(); arrarIdx++) {
					((ArrayList<Transportable>) deserializedDataObject).add((Transportable) readTransportable((Element) value.item(arrarIdx)));
				}
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	protected void deserializeHashMap(TransportField field, Object objectData, Object deserializedObject) throws TransportException {
		try {
			Class<?> genericValueClass = (Class<?>) field.getComponentValueType();

			if (field.isArray()) {
				NodeList serializedDataArray = ((Element) objectData).getChildNodes();
				HashMap[] deserializedDataArray = new HashMap[serializedDataArray.getLength()];
				for (int dataIdx = 0; dataIdx < serializedDataArray.getLength(); dataIdx++) {
					HashMap<String, Object> deserializedDataObject = (HashMap<String, Object>) ((Class<?>) field.getRawType()).newInstance();
					readHashMap(field, serializedDataArray.item(dataIdx), genericValueClass, deserializedDataObject);
					deserializedDataArray[dataIdx] = deserializedDataObject;
				}
				field.setValue(deserializedObject, deserializedDataArray);
			} else {
				HashMap<String, Object> deserializedDataObject = (HashMap<String, Object>) ((Class<?>) field.getRawType()).newInstance();
				readHashMap(field, objectData, genericValueClass, deserializedDataObject);
				field.setValue(deserializedObject, deserializedDataObject);
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void readHashMap(TransportField field, Object valueObject, Class<?> genericValueClass, Object deserializedDataObject) throws TransportException {
		try {
			NodeList value = ((Element) valueObject).getChildNodes();

			if ((Boolean.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Boolean>) deserializedDataObject).put(key, Boolean.valueOf((value.item(dataIdx + 1)).getTextContent()));
				}
			} else if ((Byte.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Byte>) deserializedDataObject).put(key, Byte.valueOf((value.item(dataIdx + 1)).getTextContent()));
				}
			} else if ((Character.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Character>) deserializedDataObject).put(key, (value.item(dataIdx + 1)).getTextContent().charAt(0));
				}
			} else if ((Short.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Short>) deserializedDataObject).put(key, Short.valueOf((value.item(dataIdx + 1)).getTextContent()));
				}
			} else if ((Integer.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Integer>) deserializedDataObject).put(key, Integer.valueOf((value.item(dataIdx + 1)).getTextContent()));
				}
			} else if ((Long.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Long>) deserializedDataObject).put(key, Long.valueOf((value.item(dataIdx + 1)).getTextContent()));
				}
			} else if ((Float.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Float>) deserializedDataObject).put(key, Float.valueOf((value.item(dataIdx + 1)).getTextContent()));
				}
			} else if ((Double.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, Double>) deserializedDataObject).put(key, Double.valueOf((value.item(dataIdx + 1)).getTextContent()));
				}
			} else if ((String.class).equals(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					((HashMap<String, String>) deserializedDataObject).put(key, (value.item(dataIdx + 1)).getTextContent());
				}
			} else if (isTransportable(genericValueClass)) {
				for (int dataIdx = 0; dataIdx < value.getLength(); dataIdx += 2) {
					String key = value.item(dataIdx).getTextContent();
					Element transportableElement = (Element) (value.item(dataIdx + 1));
					((HashMap<String, Transportable>) deserializedDataObject).put(key, (Transportable) readTransportable(transportableElement));
				}
			}
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	@Override
	protected byte[] stringify(Object serilizedData) throws TransportException {
		String theString = null;
		try {
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer trans = tf.newTransformer();
			// trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
			// "-//Apple Computer//DTD PLIST 1.0//EN");
			trans.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "http://www.apple.com/DTDs/PropertyList-1.0.dtd");
			StringWriter sw = new StringWriter();
			trans.transform(new DOMSource((Element) serilizedData), new StreamResult(sw));
			theString = sw.toString();
		} catch (Exception e) {
			throw new TransportException(e);
		}
		return theString.getBytes();

	}

	private HashMap<String, Object> readXMLElements(Node node) {
		HashMap<String, Object> xmlElement = new HashMap<String, Object>();
		NodeList childrens = node.getChildNodes();
		for (int i = 0; i < childrens.getLength(); i += 2) {
			xmlElement.put(childrens.item(i).getTextContent(), childrens.item(i + 1));
		}
		return xmlElement;

	}
}
